]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
shell-global: Make saving of persistent state asynchronous
authorCarlos Garnacho <carlosg@gnome.org>
Mon, 3 Dec 2018 12:09:47 +0000 (13:09 +0100)
committerCarlos Garnacho <mrgarnacho@gmail.com>
Mon, 28 Jan 2019 14:56:08 +0000 (14:56 +0000)
This is an expensive operation that is best avoided in the main loop. Given
the call doesn't care much about returning error or status, it can just
be made async within.

Every operation on a given file will be destructive wrt previous
operations on the same file, so we just cancel any pending operation on
it before batching the current one.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/815
src/shell-global.c

index 23d2c3f1e5149edb35deb84b1dbdd71463864f1a..c3b2555aaa364fa842f9f574b40ca513bc4a5d4f 100644 (file)
@@ -85,6 +85,8 @@ struct _ShellGlobal {
   GSList *leisure_closures;
   guint leisure_function_id;
 
+  GHashTable *save_ops;
+
   gboolean has_modal;
   gboolean frame_timestamps;
   gboolean frame_finish_timestamp;
@@ -311,6 +313,10 @@ shell_global_init (ShellGlobal *global)
                                      NULL);
 
   g_strfreev (search_path);
+
+  global->save_ops = g_hash_table_new_full (g_file_hash,
+                                            (GEqualFunc) g_file_equal,
+                                            g_object_unref, g_object_unref);
 }
 
 static void
@@ -330,6 +336,8 @@ shell_global_finalize (GObject *object)
   g_free (global->imagedir);
   g_free (global->userdatadir);
 
+  g_hash_table_unref (global->save_ops);
+
   G_OBJECT_CLASS(shell_global_parent_class)->finalize (object);
 }
 
@@ -1541,20 +1549,77 @@ shell_global_get_session_mode (ShellGlobal *global)
 }
 
 static void
-save_variant (GFile      *dir,
-              const char *property_name,
-              GVariant   *variant)
+delete_variant_cb (GObject      *object,
+                   GAsyncResult *result,
+                   gpointer      user_data)
+{
+  ShellGlobal *global = user_data;
+  GError *error = NULL;
+
+  if (!g_file_delete_finish (G_FILE (object), result, &error))
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          g_warning ("Could not delete runtime/persistent state file: %s\n",
+                     error->message);
+        }
+
+      g_error_free (error);
+    }
+
+  g_hash_table_remove (global->save_ops, object);
+}
+
+static void
+replace_variant_cb (GObject      *object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+  ShellGlobal *global = user_data;
+  GError *error = NULL;
+
+  if (!g_file_replace_contents_finish (G_FILE (object), result, NULL, &error))
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          g_warning ("Could not replace runtime/persistent state file: %s\n",
+                     error->message);
+        }
+
+      g_error_free (error);
+    }
+
+  g_hash_table_remove (global->save_ops, object);
+}
+
+static void
+save_variant (ShellGlobal *global,
+              GFile       *dir,
+              const char  *property_name,
+              GVariant    *variant)
 {
   GFile *path = g_file_get_child (dir, property_name);
+  GCancellable *cancellable;
+
+  cancellable = g_hash_table_lookup (global->save_ops, path);
+  g_cancellable_cancel (cancellable);
+
+  cancellable = g_cancellable_new ();
+  g_hash_table_insert (global->save_ops, g_object_ref (path), cancellable);
 
   if (variant == NULL || g_variant_get_data (variant) == NULL)
-    (void) g_file_delete (path, NULL, NULL);
+    {
+      g_file_delete_async (path, G_PRIORITY_DEFAULT, cancellable,
+                           delete_variant_cb, global);
+    }
   else
     {
-      gsize size = g_variant_get_size (variant);
-      g_file_replace_contents (path, g_variant_get_data (variant), size,
-                               NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
-                               NULL, NULL, NULL);
+      g_file_replace_contents_async (path,
+                                     g_variant_get_data (variant),
+                                     g_variant_get_size (variant),
+                                     NULL, FALSE,
+                                     G_FILE_CREATE_REPLACE_DESTINATION,
+                                     cancellable, replace_variant_cb, global);
     }
 
   g_object_unref (path);
@@ -1608,7 +1673,7 @@ shell_global_set_runtime_state (ShellGlobal  *global,
                                 const char   *property_name,
                                 GVariant     *variant)
 {
-  save_variant (global->runtime_state_path, property_name, variant);
+  save_variant (global, global->runtime_state_path, property_name, variant);
 }
 
 /**
@@ -1643,7 +1708,7 @@ shell_global_set_persistent_state (ShellGlobal *global,
                                    const char  *property_name,
                                    GVariant    *variant)
 {
-  save_variant (global->userdatadir_path, property_name, variant);
+  save_variant (global, global->userdatadir_path, property_name, variant);
 }
 
 /**